package main;
import java.awt.Color;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.Stack;
import java.util.Random;

public class Swarm_Agent {
		
	private Random rand;
	SearchStatus swarm_status = SearchStatus.NOTSEARCHING;
	private Stack<Location> backtrackStack = new Stack<Location>();
	private Location currentLoc;
	private int verticalBias;
	private int horizontalBias;
		
	public Swarm_Agent(int direction, Location loc)
	{
		setDirectionalBias(direction);
		currentLoc = loc;
		backtrackStack.push(currentLoc);
		rand = new Random();
		swarm_status = SearchStatus.SEARCHING;
	}
	public void draw(Graphics2D g)
	{
		g.setColor(new Color (64, 255, 0));
		g.fillRect(currentLoc.col() * 20, currentLoc.row() * 20, 20, 20);	
	}
	public void update() {
		if (swarm_status == SearchStatus.SEARCHING) {
			
			ArrayList<Location> locs = Grid.getAdjacentOpenLocations(currentLoc, 1);
			locs = removeVisited(locs);
			determinePath(selectIdealLocation(locs));
		}
	}
	public Location selectIdealLocation(ArrayList<Location> valid_locations)
	{
		if (valid_locations.isEmpty())
			return null;
		for(Location valid_loc: valid_locations)
		{
			if(Grid.isEndPoint(valid_loc))
				return valid_loc;
		}
		ArrayList<Location> possible_locations = pickFavorites(valid_locations);
		return possible_locations.get(rand.nextInt(possible_locations.size()));
	}
	public void setDirectionalBias(int direction) {
		
		switch (direction) {
		case 1: // North
			verticalBias = -1;
			horizontalBias = 0;
			break;
		case 2: // South
			verticalBias = 1;
			horizontalBias = 0;
			break;
		case 3: // East
			verticalBias = 0;
			horizontalBias = 1;
			break;
		case 4: // West
			verticalBias = 0;
			horizontalBias = -1;
			break;
		case 5: // Northeast
			verticalBias = -1;
			horizontalBias = 1;
			break;
		case 6: // Northwest
			verticalBias = -1;
			horizontalBias = -1;
			break;
		case 7: // Southeast
			verticalBias = 1;
			horizontalBias = 1;
			break;
		case 8: // Southwest
			verticalBias = 1;
			horizontalBias = -1;
			break;
		default:
			verticalBias = 0;
			horizontalBias = 0;
		
		}
	
	}
	public ArrayList<Location> pickFavorites(ArrayList<Location> valid_locations) {
		int topScore = Integer.MIN_VALUE;
		ArrayList<Location> favoriteLocs = new ArrayList<Location>();
		for (Location loc : valid_locations) {
			int score = getLocationScore(loc);
			
			if (score > topScore) {
				topScore = score;
				favoriteLocs.clear();
				favoriteLocs.add(loc);
			}
			else if (score == topScore) {
				favoriteLocs.add(loc);
			}
		}
		
		return favoriteLocs;	
	}
	public int getLocationScore(Location loc) {
		int score = 0;
		int colDifference = loc.col() - currentLoc.col();
		score += colDifference * horizontalBias;
		
		int rowDifference = loc.row() - currentLoc.row();
		score += rowDifference * verticalBias;
		return score;
	}
	
	public ArrayList<Location> removeVisited(ArrayList<Location> list) {
		ArrayList<Location> nonVisited = new ArrayList<Location>();
		for (Location loc: list) {
			if (!loc.visited) {
				nonVisited.add(loc);
			}
		}
		return nonVisited;
	}
	public void determinePath(Location plannedLocation)
	{
		if(plannedLocation != null)
		{
			if(Grid.isEndPoint(plannedLocation))
				swarm_status = SearchStatus.SUCCESSFUL;
			else
			{
				backtrackStack.push(plannedLocation);
				currentLoc = plannedLocation;
				if (Math.abs(currentLoc.row() - Simulation.grid.getStartLocation().row())> 3
						|| Math.abs(currentLoc.col() - Simulation.grid.getStartLocation().col())>3)
				currentLoc.visited = true;
				else
				{
					if (currentLoc.numTimesIgnored < Simulation.numAgents)
						currentLoc.numTimesIgnored++;
					else
						currentLoc.visited = true;
				}
			}
		}
		else
		{
			currentLoc.setBadLocation();
			if (!backtrackStack.isEmpty() && currentLoc == backtrackStack.peek()) {
				backtrackStack.pop();
			}
			if (!backtrackStack.isEmpty()) {
				currentLoc = backtrackStack.pop();
			}
			else
				swarm_status = SearchStatus.FAILURE;
		}
	}
	public SearchStatus getSuccess()
	{return swarm_status;}
}
